home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / usr / lib / python2.4 / nntplib.pyo (.txt) < prev    next >
Python Compiled Bytecode  |  2005-10-18  |  21KB  |  685 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyo (Python 2.4)
  3.  
  4. """An NNTP client class based on RFC 977: Network News Transfer Protocol.
  5.  
  6. Example:
  7.  
  8. >>> from nntplib import NNTP
  9. >>> s = NNTP('news')
  10. >>> resp, count, first, last, name = s.group('comp.lang.python')
  11. >>> print 'Group', name, 'has', count, 'articles, range', first, 'to', last
  12. Group comp.lang.python has 51 articles, range 5770 to 5821
  13. >>> resp, subs = s.xhdr('subject', first + '-' + last)
  14. >>> resp = s.quit()
  15. >>>
  16.  
  17. Here 'resp' is the server response line.
  18. Error responses are turned into exceptions.
  19.  
  20. To post an article from a file:
  21. >>> f = open(filename, 'r') # file containing article, including header
  22. >>> resp = s.post(f)
  23. >>>
  24.  
  25. For descriptions of all methods, read the comments in the code below.
  26. Note that all arguments and return values representing article numbers
  27. are strings, not numbers, since they are rarely used for calculations.
  28. """
  29. import re
  30. import socket
  31. __all__ = [
  32.     'NNTP',
  33.     'NNTPReplyError',
  34.     'NNTPTemporaryError',
  35.     'NNTPPermanentError',
  36.     'NNTPProtocolError',
  37.     'NNTPDataError',
  38.     'error_reply',
  39.     'error_temp',
  40.     'error_perm',
  41.     'error_proto',
  42.     'error_data']
  43.  
  44. class NNTPError(Exception):
  45.     '''Base class for all nntplib exceptions'''
  46.     
  47.     def __init__(self, *args):
  48.         Exception.__init__(self, *args)
  49.         
  50.         try:
  51.             self.response = args[0]
  52.         except IndexError:
  53.             self.response = 'No response given'
  54.  
  55.  
  56.  
  57.  
  58. class NNTPReplyError(NNTPError):
  59.     '''Unexpected [123]xx reply'''
  60.     pass
  61.  
  62.  
  63. class NNTPTemporaryError(NNTPError):
  64.     '''4xx errors'''
  65.     pass
  66.  
  67.  
  68. class NNTPPermanentError(NNTPError):
  69.     '''5xx errors'''
  70.     pass
  71.  
  72.  
  73. class NNTPProtocolError(NNTPError):
  74.     '''Response does not begin with [1-5]'''
  75.     pass
  76.  
  77.  
  78. class NNTPDataError(NNTPError):
  79.     '''Error in response data'''
  80.     pass
  81.  
  82. error_reply = NNTPReplyError
  83. error_temp = NNTPTemporaryError
  84. error_perm = NNTPPermanentError
  85. error_proto = NNTPProtocolError
  86. error_data = NNTPDataError
  87. NNTP_PORT = 119
  88. LONGRESP = [
  89.     '100',
  90.     '215',
  91.     '220',
  92.     '221',
  93.     '222',
  94.     '224',
  95.     '230',
  96.     '231',
  97.     '282']
  98. CRLF = '\r\n'
  99.  
  100. class NNTP:
  101.     
  102.     def __init__(self, host, port = NNTP_PORT, user = None, password = None, readermode = None, usenetrc = True):
  103.         """Initialize an instance.  Arguments:
  104.         - host: hostname to connect to
  105.         - port: port to connect to (default the standard NNTP port)
  106.         - user: username to authenticate with
  107.         - password: password to use with username
  108.         - readermode: if true, send 'mode reader' command after
  109.                       connecting.
  110.  
  111.         readermode is sometimes necessary if you are connecting to an
  112.         NNTP server on the local machine and intend to call
  113.         reader-specific comamnds, such as `group'.  If you get
  114.         unexpected NNTPPermanentErrors, you might need to set
  115.         readermode.
  116.         """
  117.         self.host = host
  118.         self.port = port
  119.         self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  120.         self.sock.connect((self.host, self.port))
  121.         self.file = self.sock.makefile('rb')
  122.         self.debugging = 0
  123.         self.welcome = self.getresp()
  124.         readermode_afterauth = 0
  125.         if readermode:
  126.             
  127.             try:
  128.                 self.welcome = self.shortcmd('mode reader')
  129.             except NNTPPermanentError:
  130.                 pass
  131.             except NNTPTemporaryError:
  132.                 e = None
  133.                 if user and e.response[:3] == '480':
  134.                     readermode_afterauth = 1
  135.                 else:
  136.                     raise 
  137.             except:
  138.                 e.response[:3] == '480'
  139.             
  140.  
  141.         None<EXCEPTION MATCH>NNTPPermanentError
  142.         
  143.         try:
  144.             if usenetrc and not user:
  145.                 import netrc as netrc
  146.                 credentials = netrc.netrc()
  147.                 auth = credentials.authenticators(host)
  148.                 if auth:
  149.                     user = auth[0]
  150.                     password = auth[2]
  151.                 
  152.         except IOError:
  153.             pass
  154.  
  155.         if user:
  156.             resp = self.shortcmd('authinfo user ' + user)
  157.             if resp[:3] == '381':
  158.                 if not password:
  159.                     raise NNTPReplyError(resp)
  160.                 else:
  161.                     resp = self.shortcmd('authinfo pass ' + password)
  162.                     if resp[:3] != '281':
  163.                         raise NNTPPermanentError(resp)
  164.                     
  165.             
  166.             if readermode_afterauth:
  167.                 
  168.                 try:
  169.                     self.welcome = self.shortcmd('mode reader')
  170.                 except NNTPPermanentError:
  171.                     pass
  172.                 except:
  173.                     None<EXCEPTION MATCH>NNTPPermanentError
  174.                 
  175.  
  176.             None<EXCEPTION MATCH>NNTPPermanentError
  177.         
  178.  
  179.     
  180.     def getwelcome(self):
  181.         '''Get the welcome message from the server
  182.         (this is read and squirreled away by __init__()).
  183.         If the response code is 200, posting is allowed;
  184.         if it 201, posting is not allowed.'''
  185.         if self.debugging:
  186.             print '*welcome*', repr(self.welcome)
  187.         
  188.         return self.welcome
  189.  
  190.     
  191.     def set_debuglevel(self, level):
  192.         """Set the debugging level.  Argument 'level' means:
  193.         0: no debugging output (default)
  194.         1: print commands and responses but not body text etc.
  195.         2: also print raw lines read and sent before stripping CR/LF"""
  196.         self.debugging = level
  197.  
  198.     debug = set_debuglevel
  199.     
  200.     def putline(self, line):
  201.         '''Internal: send one line to the server, appending CRLF.'''
  202.         line = line + CRLF
  203.         if self.debugging > 1:
  204.             print '*put*', repr(line)
  205.         
  206.         self.sock.sendall(line)
  207.  
  208.     
  209.     def putcmd(self, line):
  210.         '''Internal: send one command to the server (through putline()).'''
  211.         if self.debugging:
  212.             print '*cmd*', repr(line)
  213.         
  214.         self.putline(line)
  215.  
  216.     
  217.     def getline(self):
  218.         '''Internal: return one line from the server, stripping CRLF.
  219.         Raise EOFError if the connection is closed.'''
  220.         line = self.file.readline()
  221.         if self.debugging > 1:
  222.             print '*get*', repr(line)
  223.         
  224.         if not line:
  225.             raise EOFError
  226.         
  227.         if line[-2:] == CRLF:
  228.             line = line[:-2]
  229.         elif line[-1:] in CRLF:
  230.             line = line[:-1]
  231.         
  232.         return line
  233.  
  234.     
  235.     def getresp(self):
  236.         '''Internal: get a response from the server.
  237.         Raise various errors if the response indicates an error.'''
  238.         resp = self.getline()
  239.         if self.debugging:
  240.             print '*resp*', repr(resp)
  241.         
  242.         c = resp[:1]
  243.         if c == '4':
  244.             raise NNTPTemporaryError(resp)
  245.         
  246.         if c == '5':
  247.             raise NNTPPermanentError(resp)
  248.         
  249.         if c not in '123':
  250.             raise NNTPProtocolError(resp)
  251.         
  252.         return resp
  253.  
  254.     
  255.     def getlongresp(self, file = None):
  256.         '''Internal: get a response plus following text from the server.
  257.         Raise various errors if the response indicates an error.'''
  258.         openedFile = None
  259.         
  260.         try:
  261.             if isinstance(file, str):
  262.                 openedFile = file = open(file, 'w')
  263.             
  264.             resp = self.getresp()
  265.             if resp[:3] not in LONGRESP:
  266.                 raise NNTPReplyError(resp)
  267.             
  268.             list = []
  269.             while None:
  270.                 line = self.getline()
  271.                 if line == '.':
  272.                     break
  273.                 
  274.                 if line[:2] == '..':
  275.                     line = line[1:]
  276.                 
  277.                 if file:
  278.                     file.write(line + '\n')
  279.                     continue
  280.                 list.append(line)
  281.         finally:
  282.             if openedFile:
  283.                 openedFile.close()
  284.             
  285.  
  286.         return (resp, list)
  287.  
  288.     
  289.     def shortcmd(self, line):
  290.         '''Internal: send a command and get the response.'''
  291.         self.putcmd(line)
  292.         return self.getresp()
  293.  
  294.     
  295.     def longcmd(self, line, file = None):
  296.         '''Internal: send a command and get the response plus following text.'''
  297.         self.putcmd(line)
  298.         return self.getlongresp(file)
  299.  
  300.     
  301.     def newgroups(self, date, time, file = None):
  302.         """Process a NEWGROUPS command.  Arguments:
  303.         - date: string 'yymmdd' indicating the date
  304.         - time: string 'hhmmss' indicating the time
  305.         Return:
  306.         - resp: server response if successful
  307.         - list: list of newsgroup names"""
  308.         return self.longcmd('NEWGROUPS ' + date + ' ' + time, file)
  309.  
  310.     
  311.     def newnews(self, group, date, time, file = None):
  312.         """Process a NEWNEWS command.  Arguments:
  313.         - group: group name or '*'
  314.         - date: string 'yymmdd' indicating the date
  315.         - time: string 'hhmmss' indicating the time
  316.         Return:
  317.         - resp: server response if successful
  318.         - list: list of message ids"""
  319.         cmd = 'NEWNEWS ' + group + ' ' + date + ' ' + time
  320.         return self.longcmd(cmd, file)
  321.  
  322.     
  323.     def list(self, file = None):
  324.         '''Process a LIST command.  Return:
  325.         - resp: server response if successful
  326.         - list: list of (group, last, first, flag) (strings)'''
  327.         (resp, list) = self.longcmd('LIST', file)
  328.         for i in range(len(list)):
  329.             list[i] = tuple(list[i].split())
  330.         
  331.         return (resp, list)
  332.  
  333.     
  334.     def description(self, group):
  335.         """Get a description for a single group.  If more than one
  336.         group matches ('group' is a pattern), return the first.  If no
  337.         group matches, return an empty string.
  338.  
  339.         This elides the response code from the server, since it can
  340.         only be '215' or '285' (for xgtitle) anyway.  If the response
  341.         code is needed, use the 'descriptions' method.
  342.  
  343.         NOTE: This neither checks for a wildcard in 'group' nor does
  344.         it check whether the group actually exists."""
  345.         (resp, lines) = self.descriptions(group)
  346.         if len(lines) == 0:
  347.             return ''
  348.         else:
  349.             return lines[0][1]
  350.  
  351.     
  352.     def descriptions(self, group_pattern):
  353.         '''Get descriptions for a range of groups.'''
  354.         line_pat = re.compile('^(?P<group>[^ \t]+)[ \t]+(.*)$')
  355.         (resp, raw_lines) = self.longcmd('LIST NEWSGROUPS ' + group_pattern)
  356.         if resp[:3] != '215':
  357.             (resp, raw_lines) = self.longcmd('XGTITLE ' + group_pattern)
  358.         
  359.         lines = []
  360.         for raw_line in raw_lines:
  361.             match = line_pat.search(raw_line.strip())
  362.             if match:
  363.                 lines.append(match.group(1, 2))
  364.                 continue
  365.         
  366.         return (resp, lines)
  367.  
  368.     
  369.     def group(self, name):
  370.         '''Process a GROUP command.  Argument:
  371.         - group: the group name
  372.         Returns:
  373.         - resp: server response if successful
  374.         - count: number of articles (string)
  375.         - first: first article number (string)
  376.         - last: last article number (string)
  377.         - name: the group name'''
  378.         resp = self.shortcmd('GROUP ' + name)
  379.         if resp[:3] != '211':
  380.             raise NNTPReplyError(resp)
  381.         
  382.         words = resp.split()
  383.         count = first = last = 0
  384.         n = len(words)
  385.         if n > 1:
  386.             count = words[1]
  387.             if n > 2:
  388.                 first = words[2]
  389.                 if n > 3:
  390.                     last = words[3]
  391.                     if n > 4:
  392.                         name = words[4].lower()
  393.                     
  394.                 
  395.             
  396.         
  397.         return (resp, count, first, last, name)
  398.  
  399.     
  400.     def help(self, file = None):
  401.         '''Process a HELP command.  Returns:
  402.         - resp: server response if successful
  403.         - list: list of strings'''
  404.         return self.longcmd('HELP', file)
  405.  
  406.     
  407.     def statparse(self, resp):
  408.         '''Internal: parse the response of a STAT, NEXT or LAST command.'''
  409.         if resp[:2] != '22':
  410.             raise NNTPReplyError(resp)
  411.         
  412.         words = resp.split()
  413.         nr = 0
  414.         id = ''
  415.         n = len(words)
  416.         if n > 1:
  417.             nr = words[1]
  418.             if n > 2:
  419.                 id = words[2]
  420.             
  421.         
  422.         return (resp, nr, id)
  423.  
  424.     
  425.     def statcmd(self, line):
  426.         '''Internal: process a STAT, NEXT or LAST command.'''
  427.         resp = self.shortcmd(line)
  428.         return self.statparse(resp)
  429.  
  430.     
  431.     def stat(self, id):
  432.         '''Process a STAT command.  Argument:
  433.         - id: article number or message id
  434.         Returns:
  435.         - resp: server response if successful
  436.         - nr:   the article number
  437.         - id:   the message id'''
  438.         return self.statcmd('STAT ' + id)
  439.  
  440.     
  441.     def next(self):
  442.         '''Process a NEXT command.  No arguments.  Return as for STAT.'''
  443.         return self.statcmd('NEXT')
  444.  
  445.     
  446.     def last(self):
  447.         '''Process a LAST command.  No arguments.  Return as for STAT.'''
  448.         return self.statcmd('LAST')
  449.  
  450.     
  451.     def artcmd(self, line, file = None):
  452.         '''Internal: process a HEAD, BODY or ARTICLE command.'''
  453.         (resp, list) = self.longcmd(line, file)
  454.         (resp, nr, id) = self.statparse(resp)
  455.         return (resp, nr, id, list)
  456.  
  457.     
  458.     def head(self, id):
  459.         """Process a HEAD command.  Argument:
  460.         - id: article number or message id
  461.         Returns:
  462.         - resp: server response if successful
  463.         - nr: article number
  464.         - id: message id
  465.         - list: the lines of the article's header"""
  466.         return self.artcmd('HEAD ' + id)
  467.  
  468.     
  469.     def body(self, id, file = None):
  470.         """Process a BODY command.  Argument:
  471.         - id: article number or message id
  472.         - file: Filename string or file object to store the article in
  473.         Returns:
  474.         - resp: server response if successful
  475.         - nr: article number
  476.         - id: message id
  477.         - list: the lines of the article's body or an empty list
  478.                 if file was used"""
  479.         return self.artcmd('BODY ' + id, file)
  480.  
  481.     
  482.     def article(self, id):
  483.         '''Process an ARTICLE command.  Argument:
  484.         - id: article number or message id
  485.         Returns:
  486.         - resp: server response if successful
  487.         - nr: article number
  488.         - id: message id
  489.         - list: the lines of the article'''
  490.         return self.artcmd('ARTICLE ' + id)
  491.  
  492.     
  493.     def slave(self):
  494.         '''Process a SLAVE command.  Returns:
  495.         - resp: server response if successful'''
  496.         return self.shortcmd('SLAVE')
  497.  
  498.     
  499.     def xhdr(self, hdr, str, file = None):
  500.         """Process an XHDR command (optional server extension).  Arguments:
  501.         - hdr: the header type (e.g. 'subject')
  502.         - str: an article nr, a message id, or a range nr1-nr2
  503.         Returns:
  504.         - resp: server response if successful
  505.         - list: list of (nr, value) strings"""
  506.         pat = re.compile('^([0-9]+) ?(.*)\n?')
  507.         (resp, lines) = self.longcmd('XHDR ' + hdr + ' ' + str, file)
  508.         for i in range(len(lines)):
  509.             line = lines[i]
  510.             m = pat.match(line)
  511.             if m:
  512.                 lines[i] = m.group(1, 2)
  513.                 continue
  514.         
  515.         return (resp, lines)
  516.  
  517.     
  518.     def xover(self, start, end, file = None):
  519.         '''Process an XOVER command (optional server extension) Arguments:
  520.         - start: start of range
  521.         - end: end of range
  522.         Returns:
  523.         - resp: server response if successful
  524.         - list: list of (art-nr, subject, poster, date,
  525.                          id, references, size, lines)'''
  526.         (resp, lines) = self.longcmd('XOVER ' + start + '-' + end, file)
  527.         xover_lines = []
  528.         for line in lines:
  529.             elem = line.split('\t')
  530.             
  531.             try:
  532.                 xover_lines.append((elem[0], elem[1], elem[2], elem[3], elem[4], elem[5].split(), elem[6], elem[7]))
  533.             continue
  534.             except IndexError:
  535.                 raise NNTPDataError(line)
  536.                 continue
  537.             
  538.  
  539.         
  540.         return (resp, xover_lines)
  541.  
  542.     
  543.     def xgtitle(self, group, file = None):
  544.         '''Process an XGTITLE command (optional server extension) Arguments:
  545.         - group: group name wildcard (i.e. news.*)
  546.         Returns:
  547.         - resp: server response if successful
  548.         - list: list of (name,title) strings'''
  549.         line_pat = re.compile('^([^ \t]+)[ \t]+(.*)$')
  550.         (resp, raw_lines) = self.longcmd('XGTITLE ' + group, file)
  551.         lines = []
  552.         for raw_line in raw_lines:
  553.             match = line_pat.search(raw_line.strip())
  554.             if match:
  555.                 lines.append(match.group(1, 2))
  556.                 continue
  557.         
  558.         return (resp, lines)
  559.  
  560.     
  561.     def xpath(self, id):
  562.         '''Process an XPATH command (optional server extension) Arguments:
  563.         - id: Message id of article
  564.         Returns:
  565.         resp: server response if successful
  566.         path: directory path to article'''
  567.         resp = self.shortcmd('XPATH ' + id)
  568.         if resp[:3] != '223':
  569.             raise NNTPReplyError(resp)
  570.         
  571.         
  572.         try:
  573.             (resp_num, path) = resp.split()
  574.         except ValueError:
  575.             raise NNTPReplyError(resp)
  576.  
  577.         return (resp, path)
  578.  
  579.     
  580.     def date(self):
  581.         '''Process the DATE command. Arguments:
  582.         None
  583.         Returns:
  584.         resp: server response if successful
  585.         date: Date suitable for newnews/newgroups commands etc.
  586.         time: Time suitable for newnews/newgroups commands etc.'''
  587.         resp = self.shortcmd('DATE')
  588.         if resp[:3] != '111':
  589.             raise NNTPReplyError(resp)
  590.         
  591.         elem = resp.split()
  592.         if len(elem) != 2:
  593.             raise NNTPDataError(resp)
  594.         
  595.         date = elem[1][2:8]
  596.         time = elem[1][-6:]
  597.         if len(date) != 6 or len(time) != 6:
  598.             raise NNTPDataError(resp)
  599.         
  600.         return (resp, date, time)
  601.  
  602.     
  603.     def post(self, f):
  604.         '''Process a POST command.  Arguments:
  605.         - f: file containing the article
  606.         Returns:
  607.         - resp: server response if successful'''
  608.         resp = self.shortcmd('POST')
  609.         if resp[0] != '3':
  610.             raise NNTPReplyError(resp)
  611.         
  612.         while None:
  613.             line = f.readline()
  614.             if not line:
  615.                 break
  616.             
  617.             if line[-1] == '\n':
  618.                 line = line[:-1]
  619.             
  620.             if line[:1] == '.':
  621.                 line = '.' + line
  622.             
  623.         self.putline('.')
  624.         return self.getresp()
  625.  
  626.     
  627.     def ihave(self, id, f):
  628.         '''Process an IHAVE command.  Arguments:
  629.         - id: message-id of the article
  630.         - f:  file containing the article
  631.         Returns:
  632.         - resp: server response if successful
  633.         Note that if the server refuses the article an exception is raised.'''
  634.         resp = self.shortcmd('IHAVE ' + id)
  635.         if resp[0] != '3':
  636.             raise NNTPReplyError(resp)
  637.         
  638.         while None:
  639.             line = f.readline()
  640.             if not line:
  641.                 break
  642.             
  643.             if line[-1] == '\n':
  644.                 line = line[:-1]
  645.             
  646.             if line[:1] == '.':
  647.                 line = '.' + line
  648.             
  649.         self.putline('.')
  650.         return self.getresp()
  651.  
  652.     
  653.     def quit(self):
  654.         '''Process a QUIT command and close the socket.  Returns:
  655.         - resp: server response if successful'''
  656.         resp = self.shortcmd('QUIT')
  657.         self.file.close()
  658.         self.sock.close()
  659.         del self.file
  660.         del self.sock
  661.         return resp
  662.  
  663.  
  664. if __name__ == '__main__':
  665.     import os
  666.     if 'news':
  667.         pass
  668.     newshost = os.environ['NNTPSERVER']
  669.     if newshost.find('.') == -1:
  670.         mode = 'readermode'
  671.     else:
  672.         mode = None
  673.     s = NNTP(newshost, readermode = mode)
  674.     (resp, count, first, last, name) = s.group('comp.lang.python')
  675.     print resp
  676.     print 'Group', name, 'has', count, 'articles, range', first, 'to', last
  677.     (resp, subs) = s.xhdr('subject', first + '-' + last)
  678.     print resp
  679.     for item in subs:
  680.         print '%7s %s' % item
  681.     
  682.     resp = s.quit()
  683.     print resp
  684.  
  685.